<?php

declare(strict_types=1);

namespace App\Models;

use Carbon\Carbon;
use Hyperf\Database\Model\SoftDeletes;
use Qbhy\HyperfAuth\AuthAbility;
use Qbhy\HyperfAuth\Authenticatable;

class Agent extends Base implements Authenticatable
{
    use SoftDeletes, AuthAbility;

    /**
     * 等级: 群主
     */
    const LEVEL_GROUP_OWNER = 1;

    /**
     * 等级: 精英
     */
    const LEVEL_ELITE = 2;

    /**
     * 等级: 大咖
     */
    const LEVEL_STRONGMAN = 3;

    const LEVEL_MAP = [
        self::LEVEL_GROUP_OWNER => [
            'id' => 'group_owner',
            'text' => '群主',
            'employment' => [
                'self' => 10000 * 100, // 单位 分
                'team' => 20000 * 100
            ]
        ],
        self::LEVEL_ELITE => [
            'id' => 'elite',
            'text' => '精英',
            'employment' => [
                'self' => 80000 * 100,
                'team' => 200000 * 100
            ]
        ],
        self::LEVEL_STRONGMAN => [
            'id' => 'strongman',
            'text' => '大咖',
            'employment' => [
                'self' => 1, // 到顶级了
                'team' => 1
            ]
        ]
    ];

    /**
     * 培养奖: 开启
     */
    const CULTIVATION_AWARD_OPEN = 1;

    /**
     * 培养奖: 关闭
     */
    const CULTIVATION_AWARD_CLOSE = 2;

    /**
     * 培养奖金额 (单位 分)
     */
    const CULTIVATION_AWARD = 100;

    /**
     * 订单中间表 身份: 代理商
     */
    const AGENT_ORDER_IDENTITY_AGENT = 1;

    /**
     * 订单中间表 身份: 团队
     */
    const AGENT_ORDER_IDENTITY_TEAM = 2;

    /**
     * 订单中间表 身份: 合伙人
     */
    const AGENT_ORDER_IDENTITY_PARTNER = 3;

    /**
     * 性别: 男
     */
    const GENDER_MALE = 1;

    /**
     * 性别: 女
     */
    const GENDER_FEMALE = 2;

    /**
     * 性别对照 Map
     */
    const GENDER_CN_MAP = [
        self::GENDER_MALE => '男',
        self::GENDER_FEMALE => '女',
    ];

    protected $hidden = [
        'password',
    ];

    protected $casts = [
        'created_at' => 'datetime:Y-m-d H:i:s',
        'updated_at' => 'datetime:Y-m-d H:i:s',
        'deleted_at' => 'datetime:Y-m-d H:i:s',
        'is_agree_user_agreement' => 'bool',
        'last_time_of_login' => 'datetime:Y-m-d H:i:s',
    ];

    /**
     * 直接邀请人
     * @return \Hyperf\Database\Model\Relations\BelongsTo
     */
    public function directInviter()
    {
        return $this->belongsTo(Agent::class, 'direct_inviter');
    }

    /**
     * 间接邀请人
     * @return \Hyperf\Database\Model\Relations\BelongsTo
     */
    public function indirectInviter()
    {
        return $this->belongsTo(Agent::class, 'indirect_inviter');
    }

    /**
     * 合伙人身份
     */
    public function partnerIdentity()
    {
        return $this->hasOne(Partner::class);
    }

    /**
     * 充值订单
     * @return \Hyperf\Database\Model\Relations\HasMany
     */
    public function topUpOrder()
    {
        return $this->hasMany(AgentTopUpOrder::class);
    }

    public function wechat()
    {
        return $this->hasOne(WechatUser::class);
    }

    /**
     * 用户站内信
     */
    public function websiteLetter()
    {
        return $this->hasMany(AgentWebsiteLetter::class);
    }

    /**
     * 每日汇总
     */
    public function dailySummary()
    {
        return $this->hasMany(IndicatorsDailySummary::class);
    }

    /**
     * 每月汇总
     */
    public function monthlySummary()
    {
        return $this->hasMany(IndicatorsMonthlySummary::class);
    }

    /**
     * 每日统计
     */
    public function indicatorsDailySummary()
    {
        return $this->hasMany(IndicatorsDailySummary::class);
    }

    /**
     * 每月统计
     */
    public function indicatorsMonthlySummary()
    {
        return $this->hasMany(IndicatorsMonthlySummary::class);
    }

    /**
     * 增加 / 减少 用户(可提现)余额
     * @param $balance
     * @param $type
     * @param $related
     * @param string $method
     */
    public function incrementOrDecrementBalance($balance, $type, $related = null, $method = 'increment', \DateTimeInterface $date = null)
    {
        if ($balance <= 0) {
            return;
        }
        $date === null && $date = Carbon::now();

        // 奖金操作,操作额外累计奖金总数
        if (in_array($type, AgentRevenue::TYPE_REWARD_LIST, true)) {
            $this->{$method}('reward', $balance);
            // 自己(团队)
            $this->incrementOrDecrementTeamReward($balance, $method, $date);
            // 上级(团队)
            $this->directInviter && $this->directInviter->incrementOrDecrementTeamReward($balance, $method, $date);
            $this->indirectInviter && $this->indirectInviter->incrementOrDecrementTeamReward($balance, $method, $date);
            // 合伙人累计
            if ($this->affiliatedPartner !== null && $this->affiliatedPartner->partnerIdentity) {
                $this->affiliatedPartner->partnerIdentity->incrementOrDecrementReward($balance, $method, $date);
            }
            // 日月累计
            $this->cumulativeDailySummary(SummaryBase::TYPE_AGENT, $date, $method, 0, 0, 0, 0, $balance);
            $this->cumulativeMonthlySummary(SummaryBase::TYPE_AGENT, $date, $method, 0, 0, 0, 0, $balance);
        }
        // 佣金操作,操作额外累计佣金总数
        if (in_array($type, AgentRevenue::TYPE_COMMISSION_LIST, true)) {
            $this->{$method}('commission', $balance);
            // 自己(团队)
            $this->incrementOrDecrementTeamCommission($balance, $method, $date);
            // 上级(团队)
            $this->directInviter && $this->directInviter->incrementOrDecrementTeamCommission($balance, $method, $date);
            $this->indirectInviter && $this->indirectInviter->incrementOrDecrementTeamCommission($balance, $method, $date);
            // 合伙人累计
            if ($this->affiliatedPartner !== null && $this->affiliatedPartner->partnerIdentity) {
                $this->affiliatedPartner->partnerIdentity->incrementOrDecrementCommission($balance, $method, $date);
            }
            // 日月累计
            $this->cumulativeDailySummary(SummaryBase::TYPE_AGENT, $date, $method, 0, 0, 0, $balance);
            $this->cumulativeMonthlySummary(SummaryBase::TYPE_AGENT, $date, $method, 0, 0, 0, $balance);
        }

        $this->{$method}('balance', $balance);

        // 账单明细
        $agentRevenue = $related === null ? AgentRevenue::query() : $related->agentRevenues();
        $agentRevenue->create([
            'agent_id' => $this->getKey(),
            'revenues_type' => ['increment' => AgentRevenue::REVENUES_TYPE_INCOME, 'decrement' => AgentRevenue::REVENUES_TYPE_EXPENDITURE][$method],
            'type' => $type,
            'amount' => $balance,
            'balance' => $this['balance'],
            'unextractable_balance' => $this['unextractable_balance']
        ]);
    }

    /**
     * 增加 / 减少 用户(不可提现)余额
     * @param $balance
     * @param $type
     * @param $related
     * @param string $method
     */
    public function incrementOrDecrementUnextractableBalance($unextractableBalance, $type, $related = null, $method = 'increment')
    {
        if ($unextractableBalance <= 0) {
            return;
        }

        $this->{$method}('unextractable_balance', $unextractableBalance);

        // 账单明细
        $agentRevenue = $related === null ? AgentRevenue::query() : $related->agentRevenues();
        $agentRevenue->create([
            'agent_id' => $this->getKey(),
            'revenues_type' => ['increment' => AgentRevenue::REVENUES_TYPE_INCOME, 'decrement' => AgentRevenue::REVENUES_TYPE_EXPENDITURE][$method],
            'type' => $type,
            'amount' => $unextractableBalance,
            'balance' => $this['balance'],
            'unextractable_balance' => $this['unextractable_balance']
        ]);
    }

    /**
     * 增加 / 减少 用户(团队)奖金总和
     * @param $amount
     * @param string $method
     * @param \DateTimeInterface|null $date
     */
    public function incrementOrDecrementTeamReward($amount, $method = 'increment', \DateTimeInterface $date = null)
    {
        $amount > 0 && $this->{$method}('team_reward', $amount);

        // 日月累计
        $date === null && $date = Carbon::now();
        $amount > 0 && $this->cumulativeDailySummary(SummaryBase::TYPE_TEAM, $date, $method, 0, 0, 0, 0, $amount);
        $amount > 0 && $this->cumulativeMonthlySummary(SummaryBase::TYPE_TEAM, $date, $method, 0, 0, 0, 0, $amount);
    }

    /**
     * 累计每日汇总
     * @param $type integer 用户身份类型
     * @param \DateTimeInterface $day
     * @param string $method
     * @param int $performance
     * @param int $order
     * @param int $income
     * @param int $commission
     * @param int $reward
     */
    public function cumulativeDailySummary(
        $type, \DateTimeInterface $day, $method = 'increment',
        $performance = 0, $order = 0, $income = 0, $commission = 0, $reward = 0
    )
    {
        // 解决多次查询的优化, 这里"缓存"起来
        $dateKey = $day->format('Y-m-d');
        $dateSummaryKey = sprintf('agent_id_%d_type_%d_date_%s', $this->id, $type, $dateKey);
        if (isset($this->summaryModelCache[$dateSummaryKey])) {
            $model = $this->summaryModelCache[$dateSummaryKey];
        } else {
            $model = $this->dailySummary()->firstOrCreate(['type' => $type, 'day' => $dateKey]);
            $this->summaryModelCache[$dateSummaryKey] = $model;
        }

        $performance > 0 && $model->{$method}('performance_summary', $performance);
        $order > 0 && $model->{$method}('order_summary', $order);
        $commission > 0 && $model->{$method}('commission_summary', $commission);
        $reward > 0 && $model->{$method}('reward_summary', $reward);
        $income > 0 && $model->{$method}('income_summary', $income);
    }

    /**
     * 累计每月汇总
     * @param $type integer 用户身份类型
     * @param \DateTimeInterface $month
     * @param string $method
     * @param int $performance
     * @param int $order
     * @param int $income
     * @param int $commission
     * @param int $reward
     */
    public function cumulativeMonthlySummary(
        $type, \DateTimeInterface $month, $method = 'increment',
        $performance = 0, $order = 0, $income = 0, $commission = 0, $reward = 0
    )
    {
        // 解决多次查询的优化, 这里"缓存"起来
        $dateKey = (int) $month->format('Ym');
        $dateSummaryKey = sprintf('agent_id_%d_type_%d_date_%d', $this->id, $type, $dateKey);
        if (isset($this->summaryModelCache[$dateSummaryKey])) {
            $model = $this->summaryModelCache[$dateSummaryKey];
        } else {
            $model = $this->monthlySummary()->firstOrCreate(['type' => $type, 'month' => $dateKey]);
            $this->summaryModelCache[$dateSummaryKey] = $model;
        }

        $performance > 0 && $model->{$method}('performance_summary', $performance);
        $order > 0 && $model->{$method}('order_summary', $order);
        $commission > 0 && $model->{$method}('commission_summary', $commission);
        $reward > 0 && $model->{$method}('reward_summary', $reward);
        $income > 0 && $model->{$method}('income_summary', $income);
    }

    /**
     * 增加 / 减少 用户(团队)佣金总和
     * @param $amount
     * @param string $method
     * @param \DateTimeInterface|null $date
     */
    public function incrementOrDecrementTeamCommission($amount, $method = 'increment', \DateTimeInterface $date = null)
    {
        $amount > 0 && $this->{$method}('team_commission', $amount);

        // 日月累计
        $date === null && $date = Carbon::now();
        $amount > 0 && $this->cumulativeDailySummary(SummaryBase::TYPE_TEAM, $date, $method, 0, 0, 0, $amount);
        $amount > 0 && $this->cumulativeMonthlySummary(SummaryBase::TYPE_TEAM, $date, $method, 0, 0, 0, $amount);
    }
}
